﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using System.Threading;
using System.Text.RegularExpressions;
using TpsAutoSurvey_PDA_Version_.RealizedClasses;

namespace TpsAutoSurvey_PDA_Version_.Model
{
    public class DistantMeasureCom
    {
        AutoResetEvent wait;
        public SerialPort port;
        public bool IsProcessed { get; set; }
        public DistantMeasureCom(string comName)
        {

            wait = new AutoResetEvent(false);
            IsProcessed = false;
            port = new SerialPort();
            if (port.IsOpen == true)
                return;
            this.port = OpenPort(port, comName, 9600, 8, 300, 300);
        }
        private int tempId = -1;
        private delegate MeasureDistanceData GetMeasureValueDelegate(int id);
        private MeasureDistanceData GetMeasureValue(int id)
        {
            try
            {
                tempId = id;
                wait.Reset();
                IsProcessed = false;
                send(port, PrepareMeasureData());
                wait.WaitOne(7 * 1000, false);
                MeasureDistanceData data = GetMeasureValue();
                IsProcessed = true;
                return data;
            }
            catch (Exception a)
            {
                IsProcessed = false;
                MeasureDistanceData data = new MeasureDistanceData();
                data.Id = id;
                data.Distance = 0;
                return data;
            }
        }
        public MeasureDistanceData Measure(int id)
        {
            GetMeasureValueDelegate del = new GetMeasureValueDelegate(GetMeasureValue);
            return del.Invoke(id);
        }
        public void ClosePort()
        {
            try
            {
                if (port.IsOpen)
                {
                    port.Close();
                }
            }
            catch
            {
                return;
            }
        }
        public SerialPort OpenPort(SerialPort pp, string p_strPortName, int p_uBaudRate, int p_uDataBits, int p_uReadTimeout, int p_uWriteTimeout)
        {
            try
            {
                pp.PortName = p_strPortName;                 //COM1
                pp.BaudRate = p_uBaudRate;                   //9600
                pp.DataBits = p_uDataBits;                   //8
                pp.StopBits = StopBits.One;                  //1
                pp.Parity = Parity.None;                     //None
                pp.ReadTimeout = p_uReadTimeout;             //300
                pp.WriteTimeout = p_uWriteTimeout;           //300
                // pp.Encoding = Encoding.ASCII;
                //pp.Encoding = Encoding.Unicode;
                port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
                pp.ReadBufferSize = 8192;
                pp.DtrEnable = true;

                pp.Open();
                return pp;

            }
            catch
            {
                return null;
            }

        }
        byte[] btys;
        Thread thr = null;
        void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (IsProcessed == true)
            { return; }

            SerialPort pp = sender as SerialPort;
            btys = new byte[0];
            thr = new Thread(new ThreadStart(BeginRead));
            thr.Start();
        }
        private void send(SerialPort p, byte[] chars)
        {
            btys = new byte[1];
            p.BaseStream.Flush();
            p.Write(chars, 0, chars.Length);
            p.BaseStream.Flush();
        }
        private void BeginRead()
        {
            try
            {
                //Thread.Sleep(1200);
                IsMsgDone = false;
                port.BaseStream.Flush();
                int bytes_no = port.BytesToRead;
                byte[] bs = new byte[bytes_no];
                int bread = port.Read(bs, 0, bytes_no);
                byte[] combie = new byte[btys.Length + bs.Length];
                for (int i = 0; i < btys.Length; i++)
                {
                    combie[i] = btys[i];
                }
                for (int i = 0; i < bs.Length; i++)
                {
                    combie[i + btys.Length] = bs[i];
                }
                btys = combie;
                IsMsgComplete(btys);
                if (IsProcessed == true)
                {
                    return;
                }
                if (IsMsgDone == false)
                {
                    BeginRead();
                }
                else
                {
                    port.BaseStream.Flush();
                    return;
                }
            }
            catch
            {
                IsMsgDone = true;
            }


        }
        private string fromStrToHexStr(string str)
        {

            for (int i = 0; i < str.Length; i++)
            {
                string temp = Convert.ToString(str[i], 16);
            }
            byte[] bb = Encoding.Default.GetBytes(str);
            string hexOutput = "";
            hexOutput = BitConverter.ToString(bb).Replace("-", " ");
            return hexOutput;
        }
        private bool IsMsgDone = false;
        private bool IsMsgComplete(byte[] array)
        {
            try
            {
                if (array.Length != 11)
                {
                    IsMsgDone = false;
                    return false;
                }
                string hexOutput = "";
                hexOutput = BitConverter.ToString(array).Replace("-", " ");
                string[] hexstrs = hexOutput.Split(' ');
                string validatestr = GetValidate(hexOutput);
                if (Convert.ToInt32(validatestr, 16) == Convert.ToInt32(hexstrs[hexstrs.Length - 1], 16))
                {
                    IsMsgDone = true;
                    wait.Set();
                    return true;
                }
                else
                {
                    IsMsgDone = false;
                    return false;
                }
            }
            catch (Exception a)
            {
                return false;
            }
        }
        private string fromHexStrToStr(string Hexstr)
        {

            try
            {
                string[] hexstrs = Hexstr.Split(' ');
                byte[] bys = new byte[hexstrs.Length];
                for (int i = 0; i < hexstrs.Length; i++)
                {
                    byte b = Convert.ToByte(hexstrs[i], 16);
                    bys[i] = b;
                }
                string hexOutput = "";
                hexOutput = Encoding.ASCII.GetString(bys, 0, bys.Length);
                if (hexOutput.Length > 7)
                {
                    hexOutput = hexOutput.Substring(0, 7);
                }
                return hexOutput;
            }
            catch (Exception a)
            {

                return "";
            }
        }
        private string GetValidate(string Hexstr)
        {

            try
            {
                string[] hexstrs = Hexstr.Split(' ');
                byte[] bys = new byte[hexstrs.Length];
                int sum = 0;
                for (int i = 0; i < hexstrs.Length - 1; i++)
                {
                    int value = Convert.ToInt32(hexstrs[i], 16);
                    sum += value;
                    byte b = Convert.ToByte(value);
                    bys[i] = b;
                }
                string str = Convert.ToString(sum, 2);
                string temp = "";
                for (int j = 0; j < str.Length; j++)
                {
                    if (str[j].ToString() == "1")
                    {
                        temp += "0";
                    }
                    else
                    {
                        temp += "1";
                    }
                }
                for (int j = 8 - temp.Length; j > 0; j--)
                {
                    temp = temp.Insert(0, "1");
                }
                sum = Convert.ToInt32(temp, 2) + 1;
                str = Convert.ToString(sum, 16);
                return str.Length > 2 ?
                    str.ToUpper().Substring(str.Length - 2) :
                    str.ToUpper();
            }
            catch (Exception a)
            {


                return "1";
            }
        }
        private byte[] PrepareMeasureData()
        {
            int id = tempId;
            byte[] data = new byte[] { Convert.ToByte(id), 6, 2, 1 };
            string hexid = Convert.ToString(id, 16);
            string hexstr = hexid + " 6 2 1";
            hexstr = GetValidate(hexstr);
            data[3] = (byte)Convert.ToInt32(hexstr, 16);
            return data;
        }
        private MeasureDistanceData GetMeasureValue()
        {


            int id = 0;
            try
            {
                id = btys[0];
                if (tempId != id)
                {
                    ToolClass.Log(string.Format("{0}点号不是很一致哎", tempId));
                }
            }
            catch (Exception a)
            {
                Console.WriteLine(a.Message);
            }
            byte[] ll = new byte[btys.Length - 4];
            for (int i = 3; i <= btys.Length - 2; i++)
            {
                ll[i - 3] = btys[i];
            }
            string Hexstr = BitConverter.ToString(ll).Replace('-', ' ');
            string datastr = fromHexStrToStr(Hexstr);
            MeasureDistanceData d = new MeasureDistanceData();
            d.Id = tempId;
            try
            {
                Regex e = new Regex(@"\d+.\d+");
                if (e.Match(datastr).Success)
                {
                    datastr = e.Match(datastr).Value;
                }
                d.Distance = Convert.ToDouble(datastr);
            }
            catch (Exception a)
            {
                d.Distance = 0;
            }
            return d;
        }

    }
    public class MeasureDistanceData
    {
        public double Distance { get; set; }
        public int Id { get; set; }
        public DateTime Time { get; set; }

        public MeasureDistanceData()
        {
            Time = DateTime.Now;
        }

    }
}
